package org.tloss;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Status implements Serializable, Cloneable {

	public static int BEFFORE_MOVE = 0;
	public static int AFFTER_MAN_MOVE = 1;
	public static int AFFTER_MONSTER_MOVE = 2;
	public static int END_MOVE = 3;

	/**
	 * 
	 */
	private static final long serialVersionUID = 6820767122412421139L;
	private ArrayList<Item> items;
	private ArrayList<Item> initItems;
	private int[][] status;
	private Location manLocation;
	private Location door;
	private ArrayList<Monster> monsters = new ArrayList<Monster>();
	private int rows;
	private int cols;

	public ArrayList<Item> getInitItems() {
		return initItems;
	}

	public void setInitItems(ArrayList<Item> initItems) {
		this.initItems = initItems;
	}

	public void setManLocation(Location manLocation) {
		this.manLocation = manLocation;
	}

	public void addMonster(Monster monster) {
		monsters.add(monster);
	}

	public void initSize(int[][] status, int n, int m) {
		this.status = status;
		this.cols = n;
		this.rows = m;
		for (int i = 0; i < cols; i++) {
			status[i][0] = status[i][0] | 0x0004;
			status[i][status[0].length - 1] = status[i][status[0].length - 1] | 0x0008;
		}
		for (int i = 0; i < rows; i++) {
			status[0][i] = status[0][i] | 0x0001;
			status[status.length - 1][i] = status[status.length - 1][i] | 0x0002;
		}

	}

	public int getRows() {
		return rows;
	}

	public void setRows(int rows) {
		this.rows = rows;
	}

	public int getCols() {
		return cols;
	}

	public void setCols(int cols) {
		this.cols = cols;
	}

	public boolean canMoveLeft(int status) {
		return (status & 0x0001) == 0;
	}

	public boolean canMoveLeft(int x, int y) {

		return (x >= 0 && x < cols && y >= 0 && y < rows)
				&& canMoveLeft(status[x][y]);
	}

	public boolean canMoveRight(int status) {
		return (status & 0x0002) == 0;
	}

	public boolean canMoveRight(int x, int y) {
		return (x >= 0 && x < cols && y >= 0 && y < rows)
				&& canMoveRight(status[x][y]);
	}

	public boolean canMoveUp(int status) {
		return (status & 0x0004) == 0;
	}

	public boolean canMoveUp(int x, int y) {
		return (x >= 0 && x < cols && y >= 0 && y < rows)
				&& canMoveUp(status[x][y]);
	}

	public boolean canMoveDown(int status) {
		return (status & 0x0008) == 0;
	}

	public boolean canMoveDown(int x, int y) {
		return (x >= 0 && x < cols && y >= 0 && y < rows)
				&& canMoveDown(status[x][y]);
	}

	public void setDoor(Location door) {
		this.door = door;
	}

	public List<Item> getItems() {
		return items;
	}

	public void setItems(ArrayList<Item> items) {
		this.items = items;
	}

	public int[][] getStatus() {
		return status;
	}

	public void setStatus(int[][] status) {
		this.status = status;
	}

	public List<Monster> getMonsters() {
		return monsters;
	}

	public void setMonsters(ArrayList<Monster> monsters) {
		this.monsters = monsters;
	}

	public Location getManLocation() {
		return manLocation;
	}

	public Location getDoor() {
		return door;
	}

	@Override
	protected Object clone() throws CloneNotSupportedException {
		Status status = new Status();
		if (items != null) {
			status.items = new ArrayList<Item>();
			for (int i = 0; i < items.size(); i++) {
				status.items.add((Item) ((Item) items.get(i)).clone());
			}
		} else {
			status.items = null;
		}
		if (initItems != null) {
			status.initItems = new ArrayList<Item>();
			for (int i = 0; i < initItems.size(); i++) {
				status.initItems.add((Item) ((Item) initItems.get(i)).clone());
			}
		} else {
			status.initItems = null;
		}
		status.manLocation = (Location) manLocation.clone();
		status.door = (Location) door.clone();
		if (monsters != null) {
			status.monsters = new ArrayList<Monster>();
			for (int i = 0; i < monsters.size(); i++) {
				status.monsters.add((Monster) (monsters.get(i)).clone());
			}
		} else {
			status.monsters = null;
		}
		status.status = new int[this.status.length][];
		for (int i = 0; i < this.status.length; i++) {
			status.status[i] = Arrays.copyOf(this.status[i],
					this.status[i].length);
		}
		status.cols = cols;
		status.rows = rows;
		return status;
	}

	public boolean isLose() {
		boolean lose = false;
		for (int i = 0; !lose && i < monsters.size(); i++) {
			lose = lose || monsters.get(i).catchMan(this);
		}
		return lose;
	}

	public void itemsEffect(int type) {
		// item affect
		List<Item> items = getItems();
		for (int j = 0; items != null && j < items.size(); j++) {
			items.get(j).effect(type, this);
		}
	}

	public boolean isWin() {
		return getManLocation().equals(getDoor());
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + cols;
		result = prime * result + ((door == null) ? 0 : door.hashCode());
		result = prime * result
				+ ((initItems == null) ? 0 : initItems.hashCode());
		result = prime * result + ((items == null) ? 0 : items.hashCode());
		result = prime * result
				+ ((manLocation == null) ? 0 : manLocation.hashCode());
		result = prime * result
				+ ((monsters == null) ? 0 : monsters.hashCode());
		result = prime * result + rows;
		result = prime * result + Arrays.hashCode(status);
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Status other = (Status) obj;
		if (cols != other.cols)
			return false;
		if (door == null) {
			if (other.door != null)
				return false;
		} else if (!door.equals(other.door))
			return false;
		if (initItems == null) {
			if (other.initItems != null)
				return false;
		} else if (!initItems.equals(other.initItems))
			return false;
		if (items == null) {
			if (other.items != null)
				return false;
		} else if (!items.equals(other.items))
			return false;
		if (manLocation == null) {
			if (other.manLocation != null)
				return false;
		} else if (!manLocation.equals(other.manLocation))
			return false;
		if (monsters == null) {
			if (other.monsters != null)
				return false;
		} else if (!monsters.equals(other.monsters))
			return false;
		if (rows != other.rows)
			return false;
		if (status == other.status)
			return true;
		if (status == null || other.status == null)
			return false;
		int length = status.length;
		if (other.status.length != length)
			return false;
		for (int i = 0; i < length; i++) {
			int[] o1 = status[i];
			int[] o2 = other.status[i];
			if (!Arrays.equals(o1, o2))
				return false;
		}
		return true;
	}

}
